use std::collections::HashMap;

use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use crate::datasource::{
    ClassRelationConditionBuilder, QueryCondition, QueryConditionBuilder, QueryExtention,
    QueryExtentionBuilder, RelationConditionBuilder,
};
use crate::error::Error;
use crate::mapper::ValueMapper;
use crate::modeling::workflow::WorkflowEntity;
use crate::modeling::{
    Class, ClassAttributeBuilder, ClassBuilder, ClassGetter, ClassRelationBuilder,
    RelationRelatedType, ValueType,
};
use crate::modeling::{
    ClassAttributePersistence, ClassPersistence, ClassPersistenceBuilder, ClassPersistenceGetter,
    ClassRelation, ClassRelationGetter, Value,
};

use super::SchedulerTaskTemplate;

const SCHEDULER_TASK_CLASS_IDENTIFIER: &'static str = "g01_scheduler_task";

const SCHEDULER_TASK_CLASS_NAME: &'static str = "scheduler_task";

const SCHEDULER_TASK_TABLE_NAME: &'static str = "_g01_meta_scheduler_tasks";

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "SchedulerTaskBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct SchedulerTask {
    /// id
    pub id: i64,
    /// identifier
    pub identifier: String,
    /// 名称
    pub title: String,
    /// 任务模板
    pub template_identifier: String,
    /// 开始时间
    pub start_time: u32,
    /// 结束时间
    pub end_time: Option<u32>,
    /// cron表达式
    pub cron: String,
    /// 执行次数
    pub times: Option<u32>,
    /// 执行失败后尝试次数
    pub try_times: Option<u32>,
    /// 执行超时
    pub timeout: Option<u32>,
    /// 执行变量
    pub variables: String,
    /// 启用 禁用
    pub enable: bool,
    /// 备注
    pub description: Option<String>,
    /// 创建时间
    pub created_at: i64,
    /// 更新时间
    pub updated_at: i64,

    pub template: Option<SchedulerTaskTemplate>,
}

impl ClassGetter for SchedulerTask {
    fn get_name() -> anyhow::Result<String> {
        Ok(String::from(SCHEDULER_TASK_CLASS_NAME))
    }
    fn get_identifier() -> anyhow::Result<String> {
        Ok(String::from(SCHEDULER_TASK_CLASS_IDENTIFIER))
    }
    fn get_class() -> anyhow::Result<Class> {
        let mut attribute_builder = ClassAttributeBuilder::default();
        attribute_builder.class_identifier(SCHEDULER_TASK_CLASS_IDENTIFIER);

        let mut commons = crate::modeling::simple_attributes_with_builder(&attribute_builder)?;
        let mut append = vec![
            attribute_builder
                .clone()
                .name("identifier")
                .title("标识")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("title")
                .title("标题")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("template_identifier")
                .title("任务")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("start_time")
                .title("开始时间")
                .storage_type(ValueType::Number)
                .data_type(ValueType::Date)
                .build()?,
            attribute_builder
                .clone()
                .name("end_time")
                .title("结束时间")
                .storage_type(ValueType::Number)
                .data_type(ValueType::Date)
                .build()?,
            attribute_builder
                .clone()
                .name("cron")
                .title("corn表达式")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("try_times")
                .title("尝试次数")
                .data_type(ValueType::Number)
                .build()?,
            attribute_builder
                .clone()
                .name("timeout")
                .title("超时")
                .data_type(ValueType::Number)
                .build()?,
            attribute_builder
                .clone()
                .name("variables")
                .title("执行变量")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("enable")
                .title("启用禁用")
                .storage_type(ValueType::Number)
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("description")
                .title("描述")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("template")
                .title("模板")
                .is_persistent(false)
                .data_type(ValueType::Object)
                .build()?,
        ];
        append.append(&mut commons);
        append.sort_by(|a, b| a.position.cmp(&b.position));

        let clazz = ClassBuilder::default()
            .identifier(SCHEDULER_TASK_CLASS_IDENTIFIER)
            .name(SCHEDULER_TASK_CLASS_NAME)
            .data_is_type(true)
            .is_persistent(true)
            .primary_key(String::from("identifier"))
            .attributes(append)
            .build()?;
        Ok(clazz)
    }
}

impl ValueMapper for SchedulerTask {}
//
crate::impl_from_value!(SchedulerTask);
crate::impl_class_persistence_getter!(SchedulerTask, SCHEDULER_TASK_TABLE_NAME);
crate::impl_class_relations_getter!(
    SchedulerTask,
    vec![ClassRelationBuilder::default()
        .src_identifier(SchedulerTaskTemplate::get_identifier()?)
        .target_identifier(Self::get_identifier()?)
        .related_type(RelationRelatedType::Keys)
        .related_at("template_identifier")
        .build()?,]
);

impl SchedulerTask {
    pub fn common_query_extention() -> anyhow::Result<QueryExtention> {
        let mut ext: HashMap<String, (String, QueryCondition, Option<QueryExtention>)> =
            HashMap::new();

        let mut ext2: HashMap<String, (String, QueryCondition, Option<QueryExtention>)> =
            HashMap::new();

        ext2.insert(
            String::from("workflow"),
            (
                WorkflowEntity::get_identifier()?,
                QueryConditionBuilder::default()
                    .relations(vec![ClassRelationConditionBuilder::default()
                        .conditions(
                            RelationConditionBuilder::default()
                                .related_at("content")
                                .build()?,
                        )
                        .build()?])
                    .build()?,
                None,
            ),
        );

        ext.insert(
            String::from("template"),
            (
                SchedulerTaskTemplate::get_identifier()?,
                QueryConditionBuilder::default()
                    .relations(vec![ClassRelationConditionBuilder::default()
                        .conditions(
                            RelationConditionBuilder::default()
                                .related_at("template_identifier")
                                .build()?,
                        )
                        .build()?])
                    .build()?,
                Some(
                    QueryExtentionBuilder::default()
                        .class_selector(ext2)
                        .is_single(true)
                        .build()?,
                ),
            ),
        );
        Ok(QueryExtentionBuilder::default()
            .class_selector(ext)
            .is_single(true)
            .build()?)
    }
}
